package com.example.mcp.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * AI聊天服务类
 * 提供基于Spring AI的聊天功能，集成自定义工具
 * 
 * @author Generated
 * @version 1.0.0
 */
@Service
public class McpChatService {

    @Autowired
    private ChatClient.Builder chatClientBuilder;

    @Autowired
    private List<FunctionCallback> functionCallbacks;
    
    @Autowired
    private OpenAiChatModel chatModel;
    
    // 多会话管理：为每个 sessionId 维护独立的历史记录
    private final Map<String, InMemoryChatMemory> sessionMemories = new ConcurrentHashMap<>();
    
    // 历史记录条数限制（可配置）
    @Value("${chat.history.max-messages:20}")
    private int maxHistoryMessages;

    /**
     * 获取或创建指定会话的内存
     */
    private InMemoryChatMemory getSessionMemory(String sessionId) {
        return sessionMemories.computeIfAbsent(sessionId, k -> new InMemoryChatMemory());
    }
    
    /**
     * 从会话内存中获取历史消息
     */
    private List<Message> getHistoryMessages(String sessionId) {
        InMemoryChatMemory memory = getSessionMemory(sessionId);
        List<Message> history = memory.get(sessionId, maxHistoryMessages);
        return history != null ? new ArrayList<>(history) : new ArrayList<>();
    }
    
    /**
     * 保存消息到会话内存
     */
    private void saveMessageToHistory(String sessionId, Message message) {
        InMemoryChatMemory memory = getSessionMemory(sessionId);
        memory.add(sessionId, message);
    }

    /**
     * 处理用户聊天消息
     * 
     * @param userMessage 用户输入的消息
     * @return 响应式流，包含AI的回复
     */
    public Flux<String> chat(String userMessage) {
        try {
            System.out.println("用户消息: " + userMessage);
            System.out.println("可用工具数量: " + functionCallbacks.size());
            
            // 构建聊天客户端，启用工具调用但完全禁用历史记录
            var chatClient = chatClientBuilder
                    .defaultFunctions(functionCallbacks.toArray(new FunctionCallback[0]))  // 转换为数组
                    // 完全禁用历史记录避免循环问题
                    .build();

            // 简化的系统提示，避免复杂的指令导致问题
            String systemPrompt = "你是一个智能助手，请简洁地回答用户问题。";

            return chatClient.prompt()
                    .system(systemPrompt)
                    .user(userMessage)
                    .stream()
                    .content();
            
        } catch (Exception e) {
            System.err.println("❌ 处理聊天消息时出错: " + e.getMessage());
            e.printStackTrace();
            
            // 返回错误信息而不是抛出异常
            return Flux.just("抱歉，AI服务暂时遇到问题：" + e.getMessage() + "\n\n请稍后重试或联系管理员。");
        }
    }

    /**
     * 获取同步聊天响应 - 手动控制模式（避免无限循环）+ 历史记录支持
     * 
     * @param userMessage 用户输入的消息
     * @param sessionId 会话ID
     * @return AI的完整回复
     */
    public String chatSync(String userMessage, String sessionId) {
        try {
            System.out.println("🔄 开始同步处理用户消息（会话: " + sessionId + "）: " + userMessage);
            
            // 🔥 重置所有工具的调用计数（新请求周期）
            for (FunctionCallback callback : functionCallbacks) {
                if (callback instanceof com.example.mcp.tool.StrictMcpClientTool) {
                    ((com.example.mcp.tool.StrictMcpClientTool) callback).resetCallCount();
                }
            }

            // 构建工具映射表（用于后续查找和调用）
            Map<String, FunctionCallback> toolMap = functionCallbacks.stream()
                    .collect(Collectors.toMap(FunctionCallback::getName, tool -> tool));
            
            System.out.println("🔧 启用工具数量: " + toolMap.size());
            toolMap.forEach((name, tool) -> 
                System.out.println("  - " + name + ": " + tool.getDescription())
            );
            
            // 步骤1：准备消息列表，从历史记录加载
            List<Message> messages = new ArrayList<>();
            
            // 加载历史消息
            List<Message> historyMessages = getHistoryMessages(sessionId);
            System.out.println("📚 从会话 [" + sessionId + "] 加载历史消息数量: " + historyMessages.size());
            
            // 如果没有历史记录，添加系统提示
            if (historyMessages.isEmpty()) {
                String systemPrompt = "你是一个AI助手。根据用户请求，选择合适的工具获取信息，然后用自然语言回答用户。";
                SystemMessage systemMessage = new SystemMessage(systemPrompt);
                messages.add(systemMessage);
                saveMessageToHistory(sessionId, systemMessage);
            } else {
                // 使用历史记录
                messages.addAll(historyMessages);
            }
            
            // 添加当前用户消息
            UserMessage userMsg = new UserMessage(userMessage);
            messages.add(userMsg);
            saveMessageToHistory(sessionId, userMsg);
            
            // 步骤2：第一次调用AI（带工具定义，让AI决定是否需要调用工具）
            System.out.println("📞 第1次调用AI：询问是否需要工具...");
            
            // 提取工具名称集合
            var functionNames = functionCallbacks.stream()
                    .map(FunctionCallback::getName)
                    .collect(Collectors.toSet());
            
            OpenAiChatOptions options = OpenAiChatOptions.builder()
                    .withFunctionCallbacks(functionCallbacks)  // 提供可用工具回调
                    .withFunctions(functionNames)  // 提供工具名称集合
                    .withTemperature(0.1)
                    .withTopP(0.3)
                    .withProxyToolCalls(false)  // 🔥 禁用自动工具调用处理！关键！
                    .build();
            
            Prompt prompt = new Prompt(messages, options);
            ChatResponse response = chatModel.call(prompt);
            
            System.out.println("🔍 DEBUG: ChatResponse 结果数量: " + response.getResults().size());
            for (int i = 0; i < response.getResults().size(); i++) {
                Generation gen = response.getResults().get(i);
                System.out.println("🔍 DEBUG: 结果 " + i + " 类型: " + gen.getOutput().getClass().getName());
                if (gen.getOutput() instanceof AssistantMessage) {
                    AssistantMessage am = (AssistantMessage) gen.getOutput();
                    System.out.println("🔍 DEBUG: AssistantMessage 内容: " + (am.getContent() != null ? am.getContent().substring(0, Math.min(50, am.getContent().length())) : "null"));
                    System.out.println("🔍 DEBUG: ToolCalls 数量: " + (am.getToolCalls() != null ? am.getToolCalls().size() : "null"));
                }
            }
            
            AssistantMessage assistantMessage = (AssistantMessage) response.getResult().getOutput();
            messages.add(assistantMessage);
            
            // 步骤3：检查是否有工具调用请求
            List<AssistantMessage.ToolCall> toolCalls = assistantMessage.getToolCalls();
            
            System.out.println("🔍 DEBUG: 检查工具调用请求... toolCalls = " + (toolCalls == null ? "null" : toolCalls.size()));
            
            if (toolCalls == null || toolCalls.isEmpty()) {
                // 没有工具调用，直接返回AI的回答并保存到历史记录
                System.out.println("✅ AI直接回答（无需工具）: " + assistantMessage.getContent());
                saveMessageToHistory(sessionId, assistantMessage);
                return assistantMessage.getContent();
            }
            
            // 步骤4：执行工具调用（只执行一次，不循环）
            System.out.println("🔧 检测到工具调用请求，数量: " + toolCalls.size());
            
            // 保存包含工具调用的 AssistantMessage 到历史记录
            saveMessageToHistory(sessionId, assistantMessage);
            
            for (AssistantMessage.ToolCall toolCall : toolCalls) {
                String toolName = toolCall.name();
                String toolArgs = toolCall.arguments();
                String toolCallId = toolCall.id();
                
                System.out.println("  🛠️ 调用工具: " + toolName + ", 参数: " + toolArgs);
                
                // 查找并执行工具
                FunctionCallback tool = toolMap.get(toolName);
                if (tool == null) {
                    System.err.println("  ❌ 工具未找到: " + toolName);
                    continue;
                }
                
                // 执行工具
                String toolResult = tool.call(toolArgs);
                System.out.println("  ✅ 工具执行完成，结果: " + toolResult.substring(0, Math.min(100, toolResult.length())) + "...");
                
                // 将工具结果添加到消息列表
                // ToolResponseMessage 构造函数签名: (List<ToolResponseMessage.ToolResponse>, Map<String, Object>)
                var toolResponse = new ToolResponseMessage.ToolResponse(toolCallId, toolName, toolResult);
                ToolResponseMessage toolResponseMsg = new ToolResponseMessage(List.of(toolResponse));
                messages.add(toolResponseMsg);
                saveMessageToHistory(sessionId, toolResponseMsg);
            }
            
            // 步骤5：第二次（也是最后一次）调用AI，让它基于工具结果生成最终答案
            System.out.println("📞 第2次调用AI：基于工具结果生成最终答案...");
            
            // 添加一个明确的指令消息，告诉AI必须停止调用工具
            SystemMessage finalInstruction = new SystemMessage(
                "现在工具已经执行完成。请不要再调用任何工具。" +
                "请直接基于上面的工具返回结果，用自然语言回答用户的问题。" +
                "立即生成最终答案，不要有任何工具调用请求。"
            );
            messages.add(finalInstruction);
            // 注意：这个系统消息是临时的，不保存到历史记录
            
            // 🔥 关键修复：第二次调用时明确禁用所有工具，强制AI只能基于已有信息回答
            OpenAiChatOptions finalOptions = OpenAiChatOptions.builder()
                    .withFunctionCallbacks(List.of())  // 明确清空工具回调
                    .withFunctions(java.util.Set.of())  // 明确清空工具名称
                    .withTemperature(0.1)
                    .withTopP(0.3)
                    .build();
            
            Prompt finalPrompt = new Prompt(messages, finalOptions);
            ChatResponse finalResponse = chatModel.call(finalPrompt);
            
            AssistantMessage finalAssistantMessage = (AssistantMessage) finalResponse.getResult().getOutput();
            String finalAnswer = finalAssistantMessage.getContent();
            System.out.println("✅ 最终答案: " + finalAnswer.substring(0, Math.min(100, finalAnswer.length())) + "...");
            
            // 保存最终的 AI 回复到历史记录
            saveMessageToHistory(sessionId, finalAssistantMessage);
            
            return finalAnswer;
            
        } catch (Exception e) {
            System.err.println("❌ 同步处理聊天消息时出错: " + e.getMessage());
            e.printStackTrace();
            
            return "抱歉，AI服务暂时遇到问题：" + e.getMessage() + "\n\n请稍后重试或联系管理员。";
        }
    }



    /**
     * 清理指定会话的对话历史
     * 当AI陷入错误循环时使用
     * 
     * @param sessionId 会话ID
     */
    public void clearChatHistory(String sessionId) {
        InMemoryChatMemory memory = sessionMemories.get(sessionId);
        if (memory != null) {
            memory.clear(sessionId);
            System.out.println("✅ 已清理会话 [" + sessionId + "] 的对话历史");
        } else {
            System.out.println("⚠️ 会话 [" + sessionId + "] 不存在或已经为空");
        }
    }
    
    /**
     * 清理所有会话的对话历史
     */
    public void clearAllChatHistory() {
        int count = sessionMemories.size();
        sessionMemories.clear();
        System.out.println("✅ 已清理所有 " + count + " 个会话的对话历史");
    }

    /**
     * 获取可用工具信息
     * 
     * @return 工具信息字符串
     */
    public String getAvailableTools() {
        if (functionCallbacks.isEmpty()) {
            return "当前没有可用的自定义工具";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("可用的自定义工具 (").append(functionCallbacks.size()).append("个):\n");
        
        for (int i = 0; i < functionCallbacks.size(); i++) {
            FunctionCallback callback = functionCallbacks.get(i);
            sb.append(i + 1).append(". ").append(callback.getName())
              .append(" - ").append(callback.getDescription()).append("\n");
        }
        
        return sb.toString();
    }





    
}
